package com.gitee.hengboy.mybatis.enhance.key.generator;

import com.gitee.hengboy.mybatis.enhance.common.helper.StatementHelper;
import com.gitee.hengboy.mybatis.enhance.exception.EnhanceFrameworkException;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.RowBounds;
import org.springframework.util.ObjectUtils;

import java.sql.Statement;
import java.util.*;

/**
 * The key generator of auto-increment
 * <p>
 * Get the primary key value in auto-increment mode
 *
 * @author 恒宇少年
 */
public class SelectAutoKeyGenerator extends AbstractKeyGenerator {

    @Override
    public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
        // nothing
    }

    @Override
    protected void batchProcessBefore(MappedStatement ms, Collection<Object> statementParameters) {
        // nothing
    }

    @Override
    public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
        try {
            String selectKeySql = "select last_insert_id()";
            final Configuration configuration = ms.getConfiguration();
            Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
            MappedStatement statement = StatementHelper.createSelectKeyStatement(ms.getConfiguration(), ms.getId(), selectKeySql);

            ResultMap.Builder builder = new ResultMap.Builder(statement.getConfiguration(), statement.getId() + "-Inline", Integer.class, new ArrayList(), true);
            ResultMap resultMap = builder.build();
            MetaObject metaObject = SystemMetaObject.forObject(statement);
            metaObject.setValue("resultMaps", Collections.unmodifiableList(Arrays.asList(resultMap)));

            List<Object> values = keyExecutor.query(statement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);

            batchProcessAfter(ms, getParameters(parameter), values.get(0));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void batchProcessAfter(MappedStatement ms, Collection<Object> parameters, Object autoValue) {
        String[] keyProperties = ms.getKeyProperties();
        if (ObjectUtils.isEmpty(keyProperties)) {
            throw new EnhanceFrameworkException("并未设置主键字段，无法根据主键策略生成对应的主键值.");
        }
        String pkProperty = keyProperties[0];
        Configuration configuration = ms.getConfiguration();
        for (Object parameter : parameters) {
            MetaObject metaParam = configuration.newMetaObject(parameter);
            setPkFieldValue(metaParam, pkProperty, autoValue);
        }
    }
}

